#include <iostream>
#include <ctime>
#include <fstream>
#include <algorithm>
#include <seqan/sequence.h>
#include <seqan/file.h>
#include <seqan/translation.h>
#include <seqan/graph_align.h>
#include <seqan/graph_msa.h>
#include <seqan/seq_io.h>
#include <seqan/stream.h>

#include "gtest/gtest.h"

using namespace std;
using namespace seqan;

void Read_Files(int argc, char** argv, StringSet<CharString>& headers, StringSet<DnaString>& dnas)
{
	clear(headers);
	clear(dnas);

	for (size_t i = 1; i < argc; ++i)
	{
		string next_file(argv[i]);
		ifstream next_file_stream(next_file);
		RecordReader<ifstream, SinglePass<>> reader(next_file_stream);
		string extension = next_file.substr(next_file.rfind('.') + 1);

		CharString header;
		DnaString dna;
		if (extension == "fasta")
		{
			readRecord(header, dna, reader, Fasta());
		}
		else if (extension == "gb")
		{
			CharString buffer, key;
			readRecord(buffer, reader, GenBankHeader());
			splitGenBankHeader(key, header, buffer);
			readRecord(buffer, dna, reader, GenBank());
		}
		else
		{
			cerr << "Unsupported file type" << endl;
			throw;
		}

		appendValue(headers, header);
		appendValue(dnas, dna);
		next_file_stream.close();
	}
}

vector<double> CG_Content(StringSet<DnaString>& dnas)
{
	vector<double> cgs;
	for (DnaString dna : dnas)
	{
		double cg_content = count_if(dna.data_begin, dna.data_end, [](SimpleType<unsigned char, Dna_>& next)
		{
			return next == 'C' || next == 'G';
		}) / (double)length(dna);
		
		cgs.push_back(cg_content);
	}

	return cgs;
}

class SeqanTest: public ::testing::Test
{
protected:
	
	SeqanTest()
	{
		int argc = 4;
		char** argv = new char*[argc];
		argv[1] = "gene1.fasta";
		argv[2] = "gene2.fasta";
		argv[3] = "gene3.gb";

		Read_Files(argc, argv, headers, dnas);

		delete[] argv;
	}

	virtual ~SeqanTest()
	{
	}

	virtual void SetUp()
	{
	}

	virtual void TearDown()
	{
	}

	StringSet<CharString> headers;
	StringSet<DnaString> dnas;
};

TEST_F(SeqanTest, read_files_test)
{
	//testing headers
	string header_str(headers[0].data_begin, headers[0].data_end);
	EXPECT_STREQ(header_str.c_str(), "Bacteriophage T3 complete genome, strain Luria, gene 19");

	header_str.assign(headers[1].data_begin, headers[1].data_end);
	EXPECT_STREQ(header_str.c_str(), "Bacteriophage phiYeO3-12 complete genome, gene 19");

	header_str.assign(headers[2].data_begin, headers[2].data_end);
	EXPECT_STREQ(header_str.c_str(), "Genome                  1761 bp    DNA     linear   UNC 30-MAR-2014");

	//testing dnas
	string dna_str(dnas[0].data_begin, dnas[0].data_end);
	EXPECT_STREQ(dna_str.c_str(), "GTGTCTACTCAATCCAATCGTAATGCGCTCGTAGTGGCGCAACTGAAAGGAGACTTCGTGGCGTTCCTGTTCGTCTTATGGAAGGCGTTAAATCTTCC");

	dna_str.assign(dnas[1].data_begin, dnas[1].data_end);
	EXPECT_STREQ(dna_str.c_str(), "ATGAGCGACACCCAAGCAAACCGTAATGCGCTAATCATCGCGCAGCTTAA");

	dna_str.assign(dnas[2].data_begin, dnas[2].data_end);
	EXPECT_STREQ(dna_str.c_str(), "GTGTCTACTCAATCCAATCGTAATGCGCTCGTAGTGGCGCAACTGAAAGGAGACTTCGTGGCGTTCCTATTCGTCTTAT");
}

TEST_F(SeqanTest, cg_content_test)
{
	vector<double> answer{0.48979591836734693, 0.5, 0.48101265822784811};
	vector<double> result = CG_Content(dnas);

	for (size_t i = 0; i < answer.size(); ++i)
	{
		EXPECT_DOUBLE_EQ(answer[i], result[i]);
	}
}

TEST(Additional_Seqan_Test, multiple_alignment_test)
{
	StringSet<Peptide> peptides;
	appendValue(peptides, "AMLK");
	appendValue(peptides, "ALK");
	appendValue(peptides, "AK");

	Align<Peptide> align(peptides);
	globalMsaAlignment(align, Blosum62());

	vector<string> answer{"AMLK", "A-LK", "A--K"};
	for (size_t i = 0; i < answer.size(); ++i)
	{
		stringstream temp_s;
		temp_s << align.data_rows[i];
		EXPECT_EQ(temp_s.str(), answer[i]);
	}
}

int main(int argc, char** argv)
{
	testing::InitGoogleTest(&argc, argv);
	RUN_ALL_TESTS();
}